package puzzle.nurikabe.solver;

import puzzle.common.data.HatanException;
import puzzle.common.point.Pnt;
import puzzle.common.solver.BoardRule;
import puzzle.nurikabe.data.NurikabeBoard;
import puzzle.nurikabe.data.ShimaState;

class ShimawiseShimaPotentialRule implements BoardRule<NurikabeBoard> {

	public boolean apply(NurikabeBoard b) throws HatanException {
		boolean isChanged = false;
		for (ShimaState s : b.getShimaStates()) {
			if (s.isFixed() || !s.isDirty()) {
				continue;
			}

			if (s.getPossibleArea() == s.n) {
				for (Pnt p : s.getPossiblePoints()) {
					isChanged |= b.setShima(p.x, p.y);
				}
			} else if (s.getPossibleArea() < s.n) {
				throw new HatanException();
			} else {
				isChanged |= fill(b, s);
			}
		}
		return isChanged;
	}

	private boolean fill(NurikabeBoard b, ShimaState s) throws HatanException {
		int n = s.n;
		int i = s.n;
		while (true) {
			n -= s.getNumOfCellsPerPotential(i);
			if (n <= 0) {
				break;
			}
			i--;
		}

		boolean isChanged = false;
		for (Pnt p : s.getPossiblePoints()) {
			int k = s.getPotential(p.x, p.y);
			if (k >= i && s.getNumOfCellsPerPotential(k) == 1) {
				isChanged |= b.setShima(p.x, p.y);
			}
		}
		return isChanged;
	}

}
